import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import pandas as pd
import os
import clr
import time
import logging
from configparser import ConfigParser
import threading
from logger import DataLogger
from inca_controller import IncaController

clr.AddReference('incacom')
clr.AddReference('Etas.Base.ComSupport')
# 导入API命名空间
from de.etas.cebra.toolAPI import Inca

class ExcelReaderApp:
    def __init__(self, root):
        self.root = root
        self.root.title("INCA_AC  GUI")
        self.root.geometry("1000x600")
        pdf_path = os.getcwd() + r"\ico\eDiAT.ico"
        self.root.iconbitmap(pdf_path)


        # 新增倒计时控制变量
        self.countdown_running = False
        self.current_step = 0
        self.total_steps = 0
        # 按钮样式
        style = ttk.Style()
        style.configure('ActionAdd.TButton', foreground='white', background='#27AE60')
        style.configure('ActionDel.TButton', foreground='white', background='#E74C3C')
        style.configure('ActionClear.TButton', foreground='white', background='#95A5A6')

        # 变量存储列表
        self.variables = []

        # 初始化配置
        self.var_window = None  # 单例状态跟踪器
        self.excel_data = None
        self.openinca_data = None
        self.connect_data = None
        self.run_te = None

        self.config = ConfigParser()
        self.config_file = "app_config.ini"  # 配置文件路径
        self.file_name_var = tk.StringVar()
        self.env_name_var = tk.StringVar()
        self.length_var = tk.StringVar()
        self.numset_var = tk.StringVar()
        self.dstep_var = tk.StringVar()

        # 创建UI组件
        self.create_menu()  # 新增菜单创建
        self.create_ui()
        self.load_config()  # 初始化加载配置

        # 窗口关闭事件绑定
        self.root.protocol("WM_DELETE_WINDOW", self.on_close)

        # 响应式布局配置
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)

    def update_step_display(self):
        """更新步骤显示（线程安全）"""
        self.dstep_var.set(f"{self.current_step}/{self.total_steps}")

    def update_countdown(self, remaining):
        """更新倒计时显示（线程安全）"""
        self.length_var.set(int(remaining))

    def start_countdown(self, duration):
        """启动倒计时线程"""
        self.countdown_running = True
        threading.Thread(target=self._countdown_worker, args=(duration,)).start()

    def _countdown_worker(self, duration):
        """倒计时工作线程"""
        start_time = time.time()
        while self.countdown_running and (time.time() - start_time) < duration:
            remaining = duration - (time.time() - start_time)
            self.root.after(0, self.update_countdown, remaining)
            time.sleep(0.1)
        self.root.after(0, self.update_countdown, 0)  # 结束时归零

    def load_config(self):
        """加载配置文件"""
        if os.path.exists(self.config_file):
            self.config.read(self.config_file)
            self.file_name_var.set(self.config.get('DEFAULT', 'filename', fallback=""))
            self.env_name_var.set(self.config.get('DEFAULT', 'environment', fallback=""))
            self.numset_var.set(self.config.get('DEFAULT', 'numset', fallback=""))
            var_str = self.config.get('Variables', 'stored_vars', fallback="")
            self.variables = [v.strip() for v in var_str.split(',') if v.strip()]

    def save_config(self):
        """保存配置文件"""
        self.config['DEFAULT'] = {
            'filename': self.file_name_var.get(),
            'environment': self.env_name_var.get(),
            'numset': self.numset_var.get()
        }
        self.config['Variables'] = {'stored_vars': ','.join(self.variables)}
        with open(self.config_file, 'w') as configfile:
            self.config.write(configfile)

    def create_menu(self):
        """创建主菜单系统"""
        menubar = tk.Menu(self.root)

        # 文件菜单
        file_menu = tk.Menu(menubar, tearoff=0)
        file_menu.add_command(label=" 保存配置", command=self.save_config)
        file_menu.add_separator()
        file_menu.add_command(label=" 退出", command=self.on_close)
        menubar.add_cascade(label=" 文件", menu=file_menu)

        # 其他菜单（示例）
        for menu_label in ["查看", "设置"]:
            temp_menu = tk.Menu(menubar, tearoff=0)
            temp_menu.add_command(label=f"{menu_label} 功能待开发")
            menubar.add_cascade(label=menu_label, menu=temp_menu)

        var_menu = tk.Menu(menubar, tearoff=0)
        var_menu.add_command(label=" 变量管理面板", command=self.show_var_manager)
        menubar.add_cascade(label=" 变量管理", menu=var_menu)
        self.root.config(menu=menubar)

        help_menu = tk.Menu(menubar, tearoff=0)
        help_menu.add_command(label="操作文档PDF", command=self.show_pdf_help)
        help_menu.add_command(label="操作文档HTML", command=self.show_html_help)
        menubar.add_cascade(label=" 帮助", menu=help_menu)

    def show_pdf_help(self):
        """显示PDF帮助文档"""
        # 实现显示PDF帮助文档的逻辑
        pdf_path = os.getcwd() + r"\help\PDF\AC软件操作文档.pdf"
        os.startfile(pdf_path)
    def show_html_help(self):
        """显示PDF帮助文档"""
        # 实现显示PDF帮助文档的逻辑
        pdf_path = os.getcwd() + r"\help\HTML\AC软件操作文档.html"
        os.startfile(pdf_path)
    def show_var_manager(self):
        try:
            # 存在性检测双重验证
            if self.var_window and self.var_window.winfo_exists():
                # 窗口激活策略
                self.var_window.attributes('-topmost', 1)  # 强制置顶
                self.var_window.attributes('-topmost', 0)  # 取消置顶但保持焦点
                self.var_window.lift()  # 跨平台层级提升
                self.var_window.focus_force()  # 强制获取焦点
                return
        except tk.TclError:  # 处理窗口被强制关闭的异常
            pass
        """现代化变量管理窗口"""
        # 创建新窗口实例
        self.var_window = tk.Toplevel(self.root)
        self.var_window.transient(self.root)  # 设为模态窗口
        self.var_window.protocol("WM_DELETE_WINDOW", self.on_var_window_close)

        # 原窗口初始化代码（保持原有UI结构）
        var_win = self.var_window  # 重命名变量保持代码兼容
        var_win.title("▸   变量管理中心 ◂")
        var_win.geometry("480x360+200+200")

        # 应用主题样式
        style = ttk.Style()
        style.theme_use('clam')  # 使用简洁的clam主题
        style.configure('TButton', font=('Segoe UI', 10), padding=6)
        style.configure('TLabelframe.Label', font=('Segoe UI', 10, 'bold'))
        style.configure('TEntry', padding=5)

        # 主容器（渐变色背景）
        main_frame = ttk.Frame(var_win, style='Card.TFrame')
        main_frame.pack(fill=tk.BOTH, expand=True, padx=12, pady=12)

        # 双栏布局
        paned_window = ttk.PanedWindow(main_frame, orient=tk.HORIZONTAL)
        paned_window.pack(fill=tk.BOTH, expand=True)

        # 左侧列表区域
        list_container = ttk.Frame(paned_window, padding=5)
        paned_window.add(list_container, weight=3)

        # 立体化标题
        ttk.Label(list_container, text="▌ 已存变量列表", style='Header.TLabel',
                  font=('Microsoft YaHei', 11, 'bold'), foreground='#2C3E50').pack(anchor='w')

        # 带滚动条的列表框
        list_frame = ttk.Frame(list_container)
        list_frame.pack(fill=tk.BOTH, expand=True, pady=5)

        self.var_listbox = tk.Listbox(list_frame,
                                      bg='#F8F9FA',
                                      relief='groove',
                                      selectbackground='#3498DB',
                                      font=('Segoe UI', 10),
                                      highlightthickness=0)
        self.var_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        scrollbar = ttk.Scrollbar(list_frame, command=self.var_listbox.yview)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.var_listbox.config(yscrollcommand=scrollbar.set)

        # 右侧操作面板
        action_container = ttk.Frame(paned_window, padding=10)
        paned_window.add(action_container, weight=2)

        # 输入区域设计
        input_card = ttk.LabelFrame(action_container,
                                    text=" ▎ 变量操作 ",
                                    style='Input.TLabelframe',
                                    padding=(10, 12, 10, 10))
        input_card.pack(fill=tk.X, pady=8)

        ttk.Label(input_card,
                  text="变量名称：",
                  style='InputLabel.TLabel',
                  foreground='#34495E').grid(row=0, column=0, sticky='w')

        var_entry = ttk.Entry(input_card,
                              font=('Segoe UI', 10),
                              style='Modern.TEntry')
        var_entry.grid(row=1, column=0, pady=6, sticky='ew')
        var_entry.focus_set()

        # 按钮组（卡片式布局）
        btn_card = ttk.Frame(action_container, style='ButtonCard.TFrame')
        btn_card.pack(fill=tk.X, pady=10)

        action_btns = [
            (' 添加', 'add', '#27AE60'),
            (' 删除', 'del', '#E74C3C'),
            (' 清空', 'clear', '#95A5A6')
        ]

        for idx, (text, action, color) in enumerate(action_btns):
            btn = ttk.Button(btn_card,
                             text=text,
                             style=f'Action{action}.TButton',
                             command=lambda a=action: self.manage_var(a, var_entry.get()))
            btn.pack(side=tk.LEFT, expand=True, padx=2, ipady=3)

        # 自定义样式配置
        style.configure('Card.TFrame', background='#F0F3F4')
        style.configure('Input.TLabelframe',
                        bordercolor='#BDC3C7',
                        relief='groove',
                        font=('Segoe UI', 9, 'bold'))
        style.map('Modern.TEntry',
                  fieldbackground=[('active', '#FFFFFF'), ('!active', '#FDFEFE')])

        # 动态元素
        self.refresh_var_list()

        # 交互增强
        var_entry.bind('<Return>', lambda e: self.manage_var('add', var_entry.get()))
        self.var_listbox.bind('<Double-1>', lambda e: var_entry.insert(0, self.var_listbox.get(tk.ACTIVE)))

    def on_var_window_close(self):
        """安全关闭策略"""
        if self.var_window:
            try:
                self.var_window.destroy()  # 物理销毁窗口
                # 延迟释放资源（防止内存泄漏）
                self.root.after(100, lambda: setattr(self, 'var_window', None))
            except tk.TclError:
                pass

    def manage_var(self, action, value):
        """变量管理核心逻辑"""

        def save_and_refresh():
            self.save_config()
            self.refresh_var_list()

        if not isinstance(self.variables, list):
            messagebox.showerror("错误", "内部错误：variables 不是列表")
            return

        if action == "add":
            if not isinstance(value, str) or not value.strip():
                messagebox.showerror("错误", "请输入有效的变量名")
                return

            if len(self.variables) >= 10:
                messagebox.showerror("错误", "变量列表已满,最多只能存10个变量")
                return

            if value.strip() not in self.variables:
                self.variables.append(value.strip())
                save_and_refresh()

        elif action == "del":
            selected = self.var_listbox.curselection()
            if selected:
                try:
                    del self.variables[selected[0]]
                    save_and_refresh()
                except IndexError:
                    messagebox.showerror("错误", "选择无效")
            else:
                messagebox.showerror("错误", "请选择要删除的变量")

        elif action == "clear":
            self.variables = []
            save_and_refresh()

    def refresh_var_list(self):
        """刷新变量列表显示"""
        self.var_listbox.delete(0, tk.END)
        for var in self.variables:
            self.var_listbox.insert(tk.END, var)

    """
       创建用户界面。

       本方法负责构建应用程序的主要布局，将界面分为左侧的数据显示区域和右侧的操作区域。
       使用PanedWindow组件来实现界面的分割，以便于提供灵活的布局结构。
       """

    def create_ui(self):
        """主界面布局"""
        # 主布局分割
        main_panewindow = ttk.PanedWindow(self.root, orient=tk.HORIZONTAL)
        main_panewindow.grid(row=0, column=0, sticky="nsew")

        # 左侧数据区域
        left_frame = ttk.Frame(main_panewindow, width=800)
        self.create_data_display(left_frame)
        main_panewindow.add(left_frame, weight=3)

        # 右侧控制面板
        right_frame = ttk.Frame(main_panewindow, width=200)
        self.create_control_panel(right_frame)
        main_panewindow.add(right_frame, weight=1)

    # 重构后的数据显示组件
    def create_data_display(self, parent):
        """数据表格显示"""
        container = ttk.Frame(parent)
        container.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        self.tree = ttk.Treeview(container, columns=(), show="headings", selectmode="extended")

        # 滚动条系统
        vsb = ttk.Scrollbar(container, orient="vertical", command=self.tree.yview)
        hsb = ttk.Scrollbar(container, orient="horizontal", command=self.tree.xview)
        self.tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set)

        # 布局管理
        self.tree.grid(row=0, column=0, sticky="nsew")
        vsb.grid(row=0, column=1, sticky="ns")
        hsb.grid(row=1, column=0, sticky="ew")
        container.columnconfigure(0, weight=1)
        container.rowconfigure(0, weight=1)

    def create_control_panel(self, parent):
        """现代化控制面板"""
        style = ttk.Style()
        style.theme_use('clam')  # 使用简洁的clam主题
        style.configure('TButton', font=('Segoe UI', 10), padding=6)
        style.configure('TLabelframe.Label', font=('Segoe UI', 10, 'bold'))
        style.configure('TEntry', padding=5)

        # 主控制面板
        control_frame = ttk.LabelFrame(parent, text="▌控制中心", padding=(15, 10))
        control_frame.pack(padx=12, pady=8, fill=tk.BOTH, expand=True)

        # 操作按钮矩阵
        btn_grid = ttk.Frame(control_frame)
        btn_grid.pack(fill=tk.X, pady=(0, 10))

        actions = [
            ("📤 导入配置", self.import_excel),
            ("⚙️ 连接INCA", self.open_in),
            ("🔌 环境连接", self.open_connect),
            ("▶️ 启动测试", self.run_test),
            ("⏹️ 终止运行", self.run_stop)
        ]

        for i, (text, cmd) in enumerate(actions):
            btn = ttk.Button(btn_grid, text=text, command=cmd,
                             style='Accent.TButton' if i == 3 else 'TButton')
            btn.grid(row=i // 2, column=i % 2, padx=6, pady=6, sticky="ew")

        # 网格布局均衡分配
        btn_grid.columnconfigure(0, weight=1)
        btn_grid.columnconfigure(1, weight=1)

        # 参数配置面板
        param_frame = ttk.LabelFrame(control_frame, text="▌执行参数", padding=(15, 10))
        param_frame.pack(fill=tk.BOTH, expand=True)

        # 现代化输入组件
        input_config = [
            ("📄 文件标识", self.file_name_var, ''),
            ("🌐 试验环境", self.env_name_var, 'DEV-01'),
            ("🔢 标定数量", self.numset_var, '10'),
            ("⏳ 当前步骤", self.dstep_var, '待启动'),
            ("⏱️ 步长计数", self.length_var, '0')
        ]

        for row, (label, var, ph) in enumerate(input_config):
            ttk.Label(param_frame, text=label).grid(row=row, column=0,
                                                    padx=8, pady=6, sticky="e")
            entry = ttk.Entry(param_frame, textvariable=var,
                              font=('Consolas', 10), justify="center")
            entry.grid(row=row, column=1, padx=8, pady=6, sticky="ew")
            if row >= 3:  # 后两个为状态显示
                entry.configure(state='readonly', style='Status.TEntry')

        param_frame.columnconfigure(1, weight=1)

        # 高级样式定制
        style.map('Accent.TButton',
                  foreground=[('active', 'white'), ('!active', 'white')],
                  background=[('active', '#3B82F6'), ('!active', '#2563EB')])
        style.configure('Status.TEntry', background='#F3F4F6',
                        fieldbackground='#F3F4F6')

    def main(self):
        logger = DataLogger()
        controller = IncaController()
        TIME_VALUE_KEY = "time"
        ERROR_MSG_VARIABLES = "系统提示当前数据系统的内置变量报错，请检查内置变量"
        ERROR_MSG_MAPPING = "检测到数据映射失败，系统内置变量与 Excel 文件中的列标题存在不一致，请确认两者的变量名（包括大小写、特殊字符及拼写）完全匹配。"

        # 新增步骤统计初始化
        self.total_steps = len(self.cal_data)
        self.current_step = 0

        numset = int(self.numset_var.get())
        if numset > len(self.variables):
            messagebox.showerror(" 错误", "标定数设值必须小于等于变量列表长度")
            return

        if numset not in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:
            messagebox.showerror(" 错误", "无效的 numset 值")
            return

        try:
            variables = self.variables[:numset]
        except IndexError:
            messagebox.showerror(" 错误", ERROR_MSG_VARIABLES)
            return

        try:
            for idx, item in enumerate(self.cal_data, 1):
                if not self.run_te:
                    break

                    # 更新当前步骤显示
                self.current_step = idx
                self.root.after(0, self.update_step_display)

                time_value = float(item[TIME_VALUE_KEY])
                self.root.after(0, self.length_var.set, time_value)

                # 启动倒计时线程
                self.start_countdown(time_value)

                # 执行标定操作
                values = [float(item[var]) for var in variables]
                for var, value in zip(variables, values):
                    controller.write_calibration(self.IncaOnlineExperiment, var, value, time_value)

                # 等待当前步骤完成
                time.sleep(time_value)
                self.countdown_running = False

        except ValueError as ve:
            pass
        except Exception as e:
            print("暂停", e)
        finally:
            self.run_te = False
            self.root.after(0, lambda: messagebox.showinfo(" 提示", "测试流程已完成！"))

    def import_excel(self):
        try:
            file_path = filedialog.askopenfilename(filetypes=[("Excel 文件", "*.xlsx")])
            if not file_path: return

            df = pd.read_excel(file_path, engine='openpyxl', dtype=str, na_filter=False)
            self.cal_data = df.to_dict('records')
            if df.empty:  raise ValueError("空数据文件")

            self.tree.delete(*self.tree.get_children())
            self.tree["columns"] = cols = list(df.columns)

            for col in cols:
                self.tree.heading(col, text=col, anchor="center")
                self.tree.column(col, width=150, anchor="center")

            for _, row in df.iterrows():
                self.tree.insert("", tk.END, values=list(row))
            self.excel_data = True
            messagebox.showinfo(" 成功", f"导入 {len(df)} 行数据")
        except Exception as e:
            messagebox.showerror(" 错误", str(e))

    def open_in(self):
        threading.Thread(target=self.open_inca).start()

    def open_inca(self):
        """打开INCA程序"""
        try:
            self.inca = Inca.Inca()  # 创建INCA实例
            self.openinca_data = True
            messagebox.showinfo("提示", "INCA已启动")

        except Exception as e:
            messagebox.showerror("错误", f"启动失败：{str(e)}")

    def open_connect(self):
        threading.Thread(target=self.connect_device).start()

    def connect_device(self):
        """试验环境连接功能"""

        try:
            file_name = self.file_name_var.get()
            env_name = self.env_name_var.get()
            if self.inca.GetOpenedExperiment() is None:
                if not env_name and not file_name:
                    messagebox.showwarning(" 警告", "请输入文件名称和试验环境名称")
                else:
                    answer = messagebox.askquestion("询问", "试验环境未打开，是否打开试验环境")
                    if answer == "yes":
                        IncaDataBase = self.inca.GetCurrentDataBase()
                        IncaFolder = IncaDataBase.GetFolder(file_name)
                        if IncaFolder is None:
                            messagebox.showwarning("警告", "文件名称错误，请检查文件名称")
                        ExperimentEnvironment = IncaFolder.GetDataBaseItem(env_name)
                        if ExperimentEnvironment is None:
                            messagebox.showwarning("警告", "试验环境名称错误，请检查试验环境名称")
                        IncaExperimentView = ExperimentEnvironment.OpenExperiment()
                        self.IncaOnlineExperiment = IncaExperimentView.GetExperiment()

                        ExperimentDevice = self.IncaOnlineExperiment.GetAllDevices()
                        WorkbaseDevice = ExperimentDevice[0]
                        if not WorkbaseDevice.IsTargetOnWorkPage():  # 判断是否在参考页面
                            WorkbaseDevice.SwitchToWorkingPage()  # 切换到工作页面
                            messagebox.showinfo("提示", "已从参考切换工作页面")
                        self.connect_data = True
                        messagebox.showinfo("提示", "试验环境已打开")

                    else:
                        messagebox.showinfo("提示", "试验环境未连接，无法测量标定值")
            else:
                self.IncaOnlineExperiment = self.inca.GetOpenedExperiment()
                print(self.IncaOnlineExperiment)
                ExperimentDevice = self.IncaOnlineExperiment.GetAllDevices()
                WorkbaseDevice = ExperimentDevice[0]

                if not WorkbaseDevice.IsTargetOnWorkPage():  # 判断是否在参考页面
                    WorkbaseDevice.SwitchToWorkingPage()  # 切换到工作页面
                    messagebox.showinfo("提示", "已从参考切换工作页面")

                self.connect_data = True
                messagebox.showinfo("提示", "试验环境已连接")
        except Exception as e:
            if str(e) == "'ExcelReaderApp' object has no attribute 'inca'":
                messagebox.showerror("错误", "请先连接INCA软件")

    def run_test(self):
        """执行测试功能"""
        if not all([self.excel_data, self.openinca_data, self.connect_data]):
            messagebox.showwarning(" 警告", "请先完成所有前置步骤！")
            return
        if self.run_te:
            messagebox.showwarning(" 警告", "测试流程正在运行，请稍后再试！")
            return

            # 新增初始化步骤
        self.total_steps = len(self.cal_data)
        self.current_step = 0
        self.dstep_var.set("0/0")
        self.length_var.set("0")

        self.run_te = True
        messagebox.showinfo(" 提示", "开始执行测试流程...")
        thread = threading.Thread(target=self.main)
        thread.daemon = True  # 设置为守护线程，避免程序退出时子线程还在运行
        thread.start()

    def run_stop(self):
        """停止测试功能"""
        self.run_te = False
        messagebox.showinfo(" 提示", "测试流程已停止")

    def on_close(self):
        """窗口关闭事件处理"""
        self.countdown_running = False  # 新增关闭时停止倒计时
        self.run_te = False
        self.save_config()
        self.root.destroy()


if __name__ == "__main__":
    root = tk.Tk()
    app = ExcelReaderApp(root)
    root.mainloop()
